package com.wms.api.sfApi;


import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * 顺丰API客户端
 * 封装顺丰API调用的通用逻辑
 */
@Slf4j
@Component
public class SfApiClient {

    @Autowired
    private SfConfig sfConfig;

    /**
     * 调用顺丰API
     * @param serviceCode 服务编码
     * @param requestData 请求数据
     * @param responseClass 响应类
     * @return 响应结果
     */
    public <T> T callApi(String serviceCode, Object requestData, Class<T> responseClass) {
        try {
            // 1. 构建请求参数
            String requestJson = JSONUtil.toJsonStr(requestData);
            log.info("顺丰API请求数据: {}", requestJson);

            // 2. 生成请求ID
            String requestId = UUID.randomUUID().toString();

            // 3. 获取当前时间戳
            long timestamp = System.currentTimeMillis();

            // 4. 生成签名
            String msgDigest = generateMsgDigest(requestJson, timestamp);

            // 5. 构建form表单请求参数
            Map<String, Object> formData = new HashMap<>();
            formData.put("partnerID", sfConfig.getClientCode());
            formData.put("requestID", requestId);
            formData.put("serviceCode", serviceCode);
            formData.put("timestamp", String.valueOf(timestamp));
            formData.put("msgDigest", msgDigest);
            formData.put("msgData", requestJson);

            // 6. 发送请求
            log.info("调用顺丰API, serviceCode: {}, url: {}", serviceCode, sfConfig.getRequestUrl());
            HttpResponse response = HttpRequest.post(sfConfig.getRequestUrl())
                    .form(formData)
                    .timeout(sfConfig.getReadTimeout()) // 设置超时时间
                    .contentType("application/x-www-form-urlencoded;charset=UTF-8") // 明确指定内容类型
                    .execute();

            // 7. 处理响应
            if (response.getStatus() == 200) {
                String responseBody = response.body();
                log.info("顺丰API响应数据: {}", responseBody);
                return JSONUtil.toBean(responseBody, responseClass);
            } else {
                log.error("顺丰API调用失败, 状态码: {}", response.getStatus());
                throw new RuntimeException("顺丰API调用失败, 状态码: " + response.getStatus());
            }
        } catch (Exception e) {
            log.error("顺丰API调用异常", e);
            throw new RuntimeException("顺丰API调用异常: " + e.getMessage());
        }
    }

    /**
     * 生成数字签名
     * 签名规则: Base64(MD5(URLEncoder.encode(msgData + timestamp + checkWord, "UTF-8")))
     * 根据官方文档：msgData（业务报文）+ timestamp + checkWord(客户校验码)，
     * 经过URLEncoder.encode((msgData+timeStamp+checkWord), "UTF-8")后进行MD5，最后转换为Base64字符串
     */
    private String generateMsgDigest(String msgData, long timestamp) throws Exception {
        // 拼接原始字符串
        String data = msgData + timestamp + sfConfig.getCheckWord();
        log.debug("签名原文(未URL编码): " + data);

        // 进行URL编码
        String encodedData = URLEncoder.encode(data, StandardCharsets.UTF_8);
        log.debug("URL编码后的签名原文: " + encodedData);

        // 进行MD5摘要
        MessageDigest md5 = MessageDigest.getInstance("MD5");
        byte[] md5Bytes = md5.digest(encodedData.getBytes(StandardCharsets.UTF_8));

        // 转换为Base64字符串
        return Base64.getEncoder().encodeToString(md5Bytes);
    }
}
